import { produce } from 'immer'
import cloneDeep from 'lodash.clonedeep'
import { ComponentPropsType } from '@/components/Question'
import { getNextSelectedId } from '@/utils/getNextSelectedId'
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
import { nanoid } from 'nanoid'
import { insertNewComponent } from '@/utils/insertNewComponent'
import { arrayMove } from '@dnd-kit/sortable'

export type ComponentInfoType = {
  fe_id: string
  type: string
  title: string
  isHidden?: boolean
  isLocked?: boolean
  props: ComponentPropsType
}

export type ComponentsStateType = {
  selectedId: string
  componentList: ComponentInfoType[]
  copiedComponent: ComponentInfoType | null
}

const INIT_STATE: ComponentsStateType = {
  selectedId: '',
  componentList: [],
  //其他扩展
  copiedComponent: null,
}

export const componentsSlice = createSlice({
  name: 'components',
  initialState: INIT_STATE,
  reducers: {
    //重置所有组件
    resetComponents: produce(
      (draft: ComponentsStateType, action: PayloadAction<ComponentsStateType>) => {
        draft.componentList = action.payload.componentList
        draft.selectedId = action.payload.selectedId
      }
    ),

    //修改 selectedId
    changeSelectedId: produce((draft: ComponentsStateType, action: PayloadAction<string>) => {
      draft.selectedId = action.payload
      //react state 不可变数据 写法 immer
    }),

    //添加新组件
    addComponent: produce(
      (draft: ComponentsStateType, action: PayloadAction<ComponentInfoType>) => {
        const newComponent = action.payload
        insertNewComponent(draft, newComponent)
      }
    ),

    //修改组件属性
    changeComponentProps: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ fe_id: string; newProps: ComponentPropsType }>
      ) => {
        const { fe_id, newProps } = action.payload
        //当前要修改属性的这个组件
        const curComp = draft.componentList.find(c => c.fe_id === fe_id)
        if (curComp) {
          curComp.props = {
            ...curComp.props,
            ...newProps,
          }
        }
      }
    ),
    //删除选中的组件
    removeSelectedComponent: produce((draft: ComponentsStateType) => {
      const { componentList, selectedId } = draft

      //重新计算selectId
      const newSelectedId = getNextSelectedId(selectedId, componentList)
      draft.selectedId = newSelectedId

      const index = componentList.findIndex(c => c.fe_id === selectedId)
      componentList.splice(index, 1)
    }),

    //隐藏 / 显示 组件
    changeComponentHidden: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ fe_id: string; isHidden: boolean }>) => {
        const { componentList } = draft
        const { fe_id, isHidden } = action.payload

        //重新计算selectedId
        let newSelectedId = ''
        if (isHidden) {
          //要隐藏
          newSelectedId = getNextSelectedId(fe_id, componentList)
        } else {
          //要显示
          console.log(fe_id)
          newSelectedId = fe_id
        }
        draft.selectedId = newSelectedId

        const curComponent = componentList.find(c => c.fe_id === fe_id)
        if (curComponent) {
          curComponent.isHidden = isHidden
        }
      }
    ),

    //锁定/解锁 组件
    toggleComponentLocked: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ fe_id: string }>) => {
        const { componentList } = draft
        const { fe_id } = action.payload
        const curComponent = componentList.find(c => c.fe_id === fe_id)
        if (curComponent) {
          curComponent.isLocked = !curComponent.isLocked
        }
      }
    ),

    //拷贝当前选中的组件
    copySelectedComponent: produce((draft: ComponentsStateType) => {
      const { selectedId, componentList } = draft
      const selectedComponent = componentList.find(c => c.fe_id === selectedId)
      if (selectedComponent == null) return
      draft.copiedComponent = cloneDeep(selectedComponent) //JSON.parse(JSON.stringify(selectedComponent))
    }),

    //粘贴
    pasteCopiedComponent: produce((draft: ComponentsStateType) => {
      const { copiedComponent } = draft
      if (copiedComponent == null) return

      //要把 fe_id 给修改了 重要
      copiedComponent.fe_id = nanoid()

      //插入 copiedComponent
      insertNewComponent(draft, copiedComponent)
    }),

    //选中上一个
    selectPrevComponent: produce((draft: ComponentsStateType) => {
      const { componentList, selectedId } = draft
      const selectIndex = componentList.findIndex(c => c.fe_id === selectedId)

      if (selectIndex < 0) return //未选择组件
      if (selectIndex === 0) return //已经选中了第一个 且此时只有一个组件

      draft.selectedId = componentList[selectIndex - 1].fe_id
    }),

    selectNextComponent: produce((draft: ComponentsStateType) => {
      const { componentList, selectedId } = draft
      const selectIndex = componentList.findIndex(c => c.fe_id === selectedId)
      if (selectIndex < 0) return //未选择组件
      if (selectIndex === componentList.length - 1) return //已经选中了最后一个
      draft.selectedId = componentList[selectIndex + 1].fe_id
    }),

    //修改组件标题
    changeComponentTitle: produce(
      (draft: ComponentsStateType, action: PayloadAction<{ fe_id: string; title: string }>) => {
        const { fe_id, title } = action.payload
        const curComp = draft.componentList.find(c => c.fe_id === fe_id)
        if (curComp) curComp.title = title
      }
    ),

    //移动组件位置
    moveComponent: produce(
      (
        draft: ComponentsStateType,
        action: PayloadAction<{ oldIndex: number; newIndex: number }>
      ) => {
        const { componentList: curComponentList } = draft
        const { oldIndex, newIndex } = action.payload
        draft.componentList = arrayMove(curComponentList, oldIndex, newIndex)
      }
    ),
  },
})

export const {
  resetComponents,
  changeSelectedId,
  addComponent,
  changeComponentProps,
  removeSelectedComponent,
  changeComponentHidden,
  toggleComponentLocked,
  copySelectedComponent,
  pasteCopiedComponent,
  selectPrevComponent,
  selectNextComponent,
  changeComponentTitle,
  moveComponent,
} = componentsSlice.actions

export default componentsSlice.reducer
